/*
 * Copyright (c) 2017 Actions Semiconductor Co., Ltd
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @file
 * @brief ADC Keyboard driver for Actions SoC
 */

#include <errno.h>
#include <kernel.h>
#include <string.h>
#include <init.h>
#include <irq.h>
#include <adc.h>
#include <input_dev.h>
#include <misc/util.h>
#include <misc/byteorder.h>
#include <board.h>
#include <i2c.h>
#include <gpio.h>

#define SYS_LOG_DOMAIN "TOUCH_KEY"
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_INPUT_DEV_LEVEL
#include <logging/sys_log.h>
#define I2C_READ_ADDR 0x50
//#define MUTE_LINK_CTL 
struct touchkey_map {
	u16_t key_code;
	u16_t key_val;
};

struct acts_touchkey_data {
	struct k_timer timer;

	
	u8_t touch_buf[4];

	int scan_count;
	u16_t prev_keycode;
	u16_t prev_stable_keycode;

	input_notify_t notify;
};

struct acts_touchkey_config {
	char *touch_name;

	u16_t poll_interval_ms;
	u16_t sample_filter_dep;

	u16_t key_cnt;
	const struct touchkey_map *key_maps;
};
struct device		*gpio_dev;
static struct gpio_callback	gpio_cb;
static struct gpio_callback	exmic_gpio_cb;
#ifdef MUTE_LINK_CTL
static struct gpio_callback	mute_ctl_cb;
#endif
struct device *i2c_dev;
u8_t read_status=0;
u16_t keycode=0;
u8_t exmic_ctl_status=0;
u16_t exmic_read_cnt=0;
u8_t mute_ctl_status=0;
u8_t mute_idle_cnt=0;
u32_t prev_timestamp=0;
u32_t prev_del_io_status=0;
u8_t key_ignore=0;
#if 1
typedef struct {
	u8_t dev_addr;
	u8_t reg_addr;
} i2c_addr_t;

u32_t i2c_write_dev(void *dev, i2c_addr_t *addr, u8_t *data, u8_t num_bytes)
{
	u8_t wr_addr[2];
	u32_t ret = 0;
	struct i2c_msg msgs[2];

	if (dev == NULL) {
		ret = -1;
		SYS_LOG_ERR("%d: i2c_gpio dev is not found\n", __LINE__);
		return ret;
	}

	wr_addr[0] = addr->reg_addr;

	msgs[0].buf = wr_addr;
	msgs[0].len = 1;
	msgs[0].flags = I2C_MSG_WRITE;

	msgs[1].buf = data;
	msgs[1].len = num_bytes;
	msgs[1].flags = I2C_MSG_WRITE;

	return i2c_transfer(dev, &msgs[0], 2, addr->dev_addr);
}

u32_t i2c_read_dev(void *dev, i2c_addr_t *addr, u8_t *data, u8_t num_bytes)
{
	u8_t wr_addr[2];
	u32_t ret = 0;
	struct i2c_msg msgs[2];

	if (dev == NULL) {
		ret = -1;
		SYS_LOG_ERR("%d: i2c_gpio dev is not found\n", __LINE__);
		return ret;
	}

	wr_addr[0] = addr->reg_addr;

	msgs[0].buf = wr_addr;
	msgs[0].len = 1;
	msgs[0].flags = I2C_MSG_WRITE;

	msgs[1].buf = data;
	msgs[1].len = num_bytes;
	msgs[1].flags = I2C_MSG_READ|I2C_MSG_RESTART;

	return i2c_transfer(dev, &msgs[0], 2, addr->dev_addr);
}
void touchkey_i2C_read(u8_t Regis_Addr, u8_t *Data)
{
	u8_t i;
	int result = 0;
	u8_t readbuffer[4];
	i2c_addr_t addr;

	addr.reg_addr = Regis_Addr;
	addr.dev_addr = I2C_READ_ADDR;//NTP8808_I2C_DEV0_ADDRESS>>1;

	for (i = 0; i < 10; i++) {
		if (i2c_read_dev(i2c_dev, &addr, readbuffer, 1) == 0) {
			break;
		}
	}
	if (i == 10) {
		SYS_LOG_INF("i2c read failed\n");
		result = -1;
	}
	//printk("I2C read data:%d\n", readbuffer[0]);
	if(Data!=NULL)
	{
		Data[0]=readbuffer[0];
	}
}
#endif
#if 1

/* adc_val -> key_code */
static u16_t touchkey_acts_get_keycode(const struct acts_touchkey_config *cfg,
				     int key_val)
{
	const struct touchkey_map *map = cfg->key_maps;
	int i;

	for (i = 0; i < cfg->key_cnt; i++) {
		if (key_val ==map->key_val)
			return map->key_code;

		map++;
	}

	return KEY_RESERVED;
}

static void touchkey_acts_report_key(struct acts_touchkey_data *touchkey,
				   int key_code, int value)
{
	struct input_value val;

	if (touchkey->notify) {
		val.type = EV_KEY;
		val.code = key_code;
		val.value = value;

		//printk("report key_code %d value %d",key_code, value);

		touchkey->notify(NULL, &val);
	}
}
#endif
#if 1
static void touchkey_acts_poll(struct k_timer *timer)
{
	u32_t io_state,exmic_io_state,exmic_del_io;
	#ifdef MUTE_LINK_CTL 
	u32_t link_mute_state;
	#endif
	u8_t key_buf[4];
	struct device *dev = k_timer_user_data_get(timer);
	struct acts_touchkey_data *touchkey = dev->driver_data;
	const struct acts_touchkey_config *cfg = dev->config->config_info;
	//printk("touch device init 11111\n");
	//touchkey->touchkey_dev = device_get_binding(cfg->touch_name);
	//touchkey->touchkey_dev=device_get_binding(CONFIG_I2C_1_NAME);
	#ifdef MUTE_LINK_CTL
	if(mute_ctl_status>=3)
	{
		link_mute_state=!!(sys_read32(GPIO_REG_IDAT(GPIO_REG_BASE, BOARD_EXMIC_MUTE_CTL_PIN)) &
		    GPIO_BIT(BOARD_EXMIC_MUTE_CTL_PIN));
		if(link_mute_state)
		{
			mute_idle_cnt++;
		}
		else
		{
			mute_idle_cnt=0;
		}
		printk("mute_idle_cnt:%d\n",mute_idle_cnt);
		if(mute_idle_cnt==2)
		{
			//mute_idle_cnt=0;
			if(mute_ctl_status==4)
			{
				touchkey_acts_report_key(touchkey, KEY_MUTE_SYNC_CTL, 1);
			}
			else if(mute_ctl_status==3)
			{
				touchkey_acts_report_key(touchkey, KEY_UNMUTE_SYNC_CTL, 1);
			}
		}
		else if(mute_idle_cnt>4)
		{			
			if(mute_ctl_status==4)
			{
				touchkey_acts_report_key(touchkey, KEY_MUTE_SYNC_CTL, 0);
			}
			else if(mute_ctl_status==3)
			{
				touchkey_acts_report_key(touchkey, KEY_UNMUTE_SYNC_CTL, 0);
			}
			mute_idle_cnt=0;
			mute_ctl_status=0;
		}
	}
	#endif
	if(exmic_ctl_status)
	{
		exmic_io_state=!!(sys_read32(GPIO_REG_IDAT(GPIO_REG_BASE, BOARD_EXMIC_MUTE_DEL_PIN)) &
		    GPIO_BIT(BOARD_EXMIC_MUTE_DEL_PIN));
		#ifdef BOARD_MICIN_DETECT_GPIO
		exmic_del_io=!!(sys_read32(GPIO_REG_IDAT(GPIO_REG_BASE, BOARD_MICIN_DETECT_GPIO)) &
		    GPIO_BIT(BOARD_MICIN_DETECT_GPIO));
		#else
		exmic_del_io=1;
		#endif
		exmic_read_cnt++;
		printk("exmic_io:%d->del io 11:%d\n",exmic_io_state,exmic_del_io);
		#if 0
		if(exmic_io_state==0)
		{
			printk("exmic_read_cnt low:%d\n",exmic_read_cnt);
		}
		else
		{
			printk("exmic_read_cnt high:%d\n",exmic_read_cnt);
			exmic_read_cnt=0;
		}
		#endif
		#if 1
		if(exmic_del_io==0&&exmic_read_cnt<5)
		{
			exmic_ctl_status=0;
			exmic_read_cnt=0;
			key_ignore=0;
		}
		else if(exmic_io_state==0&&exmic_read_cnt<5)
		{
			exmic_ctl_status=0;
			exmic_read_cnt=0;
			key_ignore=0;
		}
		else if(exmic_read_cnt==5)
		{
			if(key_ignore)
			{
				
			}
			else
			{
				touchkey_acts_report_key(touchkey, KEY_MUTE_CTL, 1);
			}
			
		}
		else if(exmic_read_cnt>7)
		{
			if(key_ignore)
			{
				
			}
			else
			{
				touchkey_acts_report_key(touchkey, KEY_MUTE_CTL, 0);
			}
			exmic_ctl_status=0;
			exmic_read_cnt=0;
			key_ignore=0;
			
		}
		#endif
	}
	io_state = !!(sys_read32(GPIO_REG_IDAT(GPIO_REG_BASE, BOARD_I2C1_INT_PIN)) &
		    GPIO_BIT(BOARD_I2C1_INT_PIN));
	//printk("value:%d\n",value);
	if ((read_status==0)&&(io_state !=0)&&(touchkey->prev_stable_keycode == KEY_RESERVED))
	{
		read_status=0;
		keycode=0;
		return;
	}
	if(read_status==1)
	{
		read_status=2;
		touchkey_i2C_read(0xA1,key_buf);
		keycode = touchkey_acts_get_keycode(cfg,key_buf[0]);
		
	}
	else if((io_state !=0)&&(read_status!=0))
	{
		keycode=0;
		read_status=0;
		//printk("1111111\n");
	}
	//printk("keycode:%d->prev_keycode:%d\n",keycode,touchkey->prev_keycode);
	if (keycode == touchkey->prev_keycode) {
		touchkey->scan_count++;
		if (touchkey->scan_count == cfg->sample_filter_dep) {
			/* previous key is released? */
			if (touchkey->prev_stable_keycode != KEY_RESERVED
				&& keycode != touchkey->prev_stable_keycode)
				touchkey_acts_report_key(touchkey,
					touchkey->prev_stable_keycode, 0);

			/* a new key press? */
			if (keycode != KEY_RESERVED)
				touchkey_acts_report_key(touchkey, keycode, 1);

			/* clear counter for new checking */
			touchkey->prev_stable_keycode = keycode;
			touchkey->scan_count = 0;
		}
	} else {
		/* new key pressed? */
		touchkey->prev_keycode = keycode;
		touchkey->scan_count = 0;
	}
	#if 0
	if(read_status==1)
	{
		read_status=2;
		printk("read start!\n");
		touchkey_i2C_read(0xA1,NULL);
		read_status=0;
		printk("read end!\n");
	}
	#endif
	
}
#endif
static void touchkey_acts_enable(struct device *dev)
{
	//const struct acts_touchkey_config *cfg = dev->config->config_info;
	struct acts_touchkey_data *touchkey = dev->driver_data;

	printk("enable adckey\n");

	//adc_enable(touchkey->adc_dev);
	k_timer_start(&touchkey->timer, 500,
		20);
}

static void touchkey_acts_disable(struct device *dev)
{
	struct acts_touchkey_data *touchkey = dev->driver_data;

	printk("disable adckey\n");

	k_timer_stop(&touchkey->timer);
	//adc_disable(touchkey->adc_dev);

	//adckey->notify = NULL;
}

static void touchkey_acts_register_notify(struct device *dev, input_notify_t notify)
{
	struct acts_touchkey_data *touchkey = dev->driver_data;

	SYS_LOG_INF("register notify 0x%x", (u32_t)notify);

	touchkey->notify = notify;
}

static void touchkey_acts_unregister_notify(struct device *dev, input_notify_t notify)
{
	struct acts_touchkey_data *touchkey = dev->driver_data;

	SYS_LOG_INF("unregister notify 0x%x", (u32_t)notify);

	touchkey->notify = NULL;
}

const struct input_dev_driver_api touchkey_acts_driver_api = {
	.enable = touchkey_acts_enable,
	.disable = touchkey_acts_disable,
	.register_notify = touchkey_acts_register_notify,
	.unregister_notify = touchkey_acts_unregister_notify,
};
static void touch_key_io_isr(struct device *unused1, struct gpio_callback *unused2,
			unsigned int unused3)
{
	//k_sem_give(&sem_request);
	read_status=1;
	//printk("gpio int!!\n");
}

static void exmic_ctl_io_isr(struct device *unused1, struct gpio_callback *unused2,
			unsigned int unused3)
{
	//k_sem_give(&sem_request);
	u32_t exmic_io_state,exmic_del_io=0,cur_timestamp;
	exmic_ctl_status=1;
	exmic_io_state=!!(sys_read32(GPIO_REG_IDAT(GPIO_REG_BASE, BOARD_EXMIC_MUTE_DEL_PIN)) &
		    GPIO_BIT(BOARD_EXMIC_MUTE_DEL_PIN));
	#ifdef BOARD_MICIN_DETECT_GPIO
	exmic_del_io=!!(sys_read32(GPIO_REG_IDAT(GPIO_REG_BASE, BOARD_MICIN_DETECT_GPIO)) &
		    GPIO_BIT(BOARD_MICIN_DETECT_GPIO));
	#endif
	cur_timestamp=k_uptime_get_32();
	printk("exmic_io:%d->del io:%d\n",exmic_io_state,exmic_del_io);
	if((cur_timestamp-prev_timestamp<400)&&prev_del_io_status==0&&exmic_del_io==1)
	{
		key_ignore=1;
		printk("timeoffset:%d\n",cur_timestamp-prev_timestamp);
	}
	prev_del_io_status=exmic_del_io;
	prev_timestamp=cur_timestamp;
	
	//printk("exmic gpio int!!\n");
}
#ifdef MUTE_LINK_CTL
static void mute_ctl_io_isr(struct device *unused1, struct gpio_callback *unused2,unsigned int unused3)
{
	//k_sem_give(&sem_request);
	//u32_t link_mute_state;
	mute_ctl_status++;
	printk("mute link cnt:%d\n",mute_ctl_status);
	#if 0
	link_mute_state=!!(sys_read32(GPIO_REG_IDAT(GPIO_REG_BASE, BOARD_EXMIC_MUTE_CTL_PIN)) &
		    GPIO_BIT(BOARD_EXMIC_MUTE_CTL_PIN));
	printk("link_mute:%d\n",link_mute_state);
	#endif
	//printk("exmic gpio int!!\n");
}
#endif
int touchkey_acts_init(struct device *dev)
{
	//const struct acts_touchkey_config *cfg = dev->config->config_info;
	struct acts_touchkey_data *touchkey = dev->driver_data;
	//printk("touch device init 11111\n");
	//touchkey->touchkey_dev = device_get_binding(cfg->touch_name);
	i2c_dev=device_get_binding(CONFIG_I2C_GPIO_0_NAME);
	if (!i2c_dev) {
		printk("cannot found I2C dev %s\n", CONFIG_I2C_GPIO_0_NAME);
		return -ENODEV;
	}
	//printk("touch device init\n");
	i2c_configure(i2c_dev, I2C_SPEED_FAST | I2C_MODE_MASTER);
	//i2c_configure(touchkey->touchkey_dev, I2C_SPEED_FAST | I2C_MODE_MASTER);
	gpio_dev=device_get_binding(CONFIG_GPIO_ACTS_DEV_NAME);
	if (!gpio_dev) {
		SYS_LOG_INF("cannot found gpio_dev %s\n", CONFIG_GPIO_ACTS_DEV_NAME);
		return -ENODEV;
	}
	gpio_pin_configure(gpio_dev, BOARD_I2C1_INT_PIN,
			   GPIO_DIR_IN | GPIO_INT |
			   GPIO_INT_EDGE | GPIO_INT_ACTIVE_LOW);
	gpio_init_callback(&gpio_cb, touch_key_io_isr, BIT(BOARD_I2C1_INT_PIN));
	if (gpio_add_callback(gpio_dev, &gpio_cb)) {
		return -EINVAL;
	}

	if (gpio_pin_enable_callback(gpio_dev, BOARD_I2C1_INT_PIN)) {
		return -EINVAL;
	}

	
	gpio_pin_configure(gpio_dev, BOARD_EXMIC_MUTE_DEL_PIN,
			   GPIO_DIR_IN | GPIO_INT |
			   GPIO_INT_EDGE | GPIO_INT_ACTIVE_HIGH);

  
   gpio_init_callback(&exmic_gpio_cb, exmic_ctl_io_isr, BIT(BOARD_EXMIC_MUTE_DEL_PIN));
	if (gpio_add_callback(gpio_dev, &exmic_gpio_cb)) {
		return -EINVAL;
	}
	#ifdef MUTE_LINK_CTL
	gpio_pin_configure(gpio_dev, BOARD_EXMIC_MUTE_CTL_PIN,
    GPIO_DIR_IN | GPIO_INT |
    GPIO_INT_EDGE | GPIO_INT_ACTIVE_LOW);
	gpio_init_callback(&mute_ctl_cb, mute_ctl_io_isr, BIT(BOARD_EXMIC_MUTE_CTL_PIN));
	if (gpio_add_callback(gpio_dev, &mute_ctl_cb)) {
		return -EINVAL;
	}
	#endif

	k_timer_init(&touchkey->timer, touchkey_acts_poll, NULL);
	k_timer_user_data_set(&touchkey->timer, dev);

	return 0;
}

static struct acts_touchkey_data touchkey_acts_ddata;
#if 1
static const struct touchkey_map touchkey_acts_keymaps[] = {
#ifdef BOARD_TOUCHKEY_KEY_MAPPINGS
	BOARD_TOUCHKEY_KEY_MAPPINGS
#endif
};
static const struct acts_touchkey_config touchkey_acts_cdata = {
	.touch_name = CONFIG_I2C_GPIO_0_NAME,
	.poll_interval_ms = 20,
	.sample_filter_dep = 3,

	.key_cnt = ARRAY_SIZE(touchkey_acts_keymaps),
	.key_maps = &touchkey_acts_keymaps[0],
};
#endif
DEVICE_AND_API_INIT(touch_key_acts, CONFIG_INPUT_DEV_ACTS_TOUCHKEY_NAME,
		    touchkey_acts_init,
		    &touchkey_acts_ddata, &touchkey_acts_cdata,
		    POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
		    &touchkey_acts_driver_api);
